package com.fplanning.planner.domain;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import com.fplanning.planner.business.WeightSlicer;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.drools.planner.api.domain.solution.PlanningEntityCollectionProperty;
import org.drools.planner.core.score.buildin.hardandsoft.HardAndSoftScore;
import org.drools.planner.core.solution.Solution;
import org.drools.planner.examples.common.domain.AbstractPersistable;

public class FinancialPlan implements Solution<HardAndSoftScore>
{

    private List<IFinancialInstrument> financialInstrumentList;

    private List<List<FISlice>> fiSlicesList;

    private List<YearlyPlan> yearlyPlanList;

    private HardAndSoftScore score;

    @PlanningEntityCollectionProperty
    public List<YearlyPlan> getYearlyPlanList()
    {
        return yearlyPlanList;
    }

    public void setYearlyPlanList(List<YearlyPlan> yearlyPlanList)
    {
        this.yearlyPlanList = yearlyPlanList;
    }

    public HardAndSoftScore getScore()
    {
        return score;
    }

    public void setScore(HardAndSoftScore score)
    {
        this.score = score;
    }

    // ************************************************************************
    // Complex methods
    // ************************************************************************

    public Collection<? extends Object> getProblemFacts()
    {
        List<Object> facts = new ArrayList<Object>();
        facts.addAll(fiSlicesList);
        // Do not add the planning entity's (processList) because that will be
        // done automatically
        return facts;
    }

    /**
     * Clone will only deep copy the {@link #yearlyPlanList}.
     */
    public FinancialPlan cloneSolution()
    {
        FinancialPlan clone = new FinancialPlan();
        clone.fiSlicesList = fiSlicesList;
        List<YearlyPlan> clonedProcessList = new ArrayList<YearlyPlan>(
                yearlyPlanList.size());
        for (YearlyPlan process : yearlyPlanList)
        {
            YearlyPlan clonedProcess = process.clone();
            clonedProcessList.add(clonedProcess);
        }
        clone.yearlyPlanList = clonedProcessList;
        clone.score = score;
        return clone;
    }

    public boolean equals(Object o)
    {
        if (this == o)
        {
            return true;
        }
        if (!(o instanceof FinancialPlan))
        {
            return false;
        }
        else
        {
            FinancialPlan other = (FinancialPlan) o;
            if (yearlyPlanList.size() != other.yearlyPlanList.size())
            {
                return false;
            }
            for (Iterator<YearlyPlan> it = yearlyPlanList.iterator(), otherIt = other.yearlyPlanList
                    .iterator(); it.hasNext();)
            {
                YearlyPlan process = it.next();
                YearlyPlan otherProcess = otherIt.next();
                // Notice: we don't use equals()
                if (!process.solutionEquals(otherProcess))
                {
                    return false;
                }
            }
            return true;
        }
    }

    public int hashCode()
    {
        HashCodeBuilder hashCodeBuilder = new HashCodeBuilder();
        for (YearlyPlan process : yearlyPlanList)
        {
            // Notice: we don't use hashCode()
            hashCodeBuilder.append(process.solutionHashCode());
        }
        return hashCodeBuilder.toHashCode();
    }

    /**
     * @return the financialInstrumentList
     */
    public final List<IFinancialInstrument> getFinancialInstrumentList()
    {
        return financialInstrumentList;
    }

    /**
     * @param financialInstrumentList
     *            the financialInstrumentList to set
     */
    public final void setFinancialInstrumentList(
            List<IFinancialInstrument> financialInstrumentList)
    {
        this.financialInstrumentList = financialInstrumentList;
    }

    /**
     * @return the fiSlicesList
     */
    public final List<List<FISlice>> getFiSlicesList()
    {
        return fiSlicesList;
    }

    /**
     * @param fiSlicesList
     *            the fiSlicesList to set
     */
    public final void setFiSlicesList(List<List<FISlice>> fiSlicesList)
    {
        this.fiSlicesList = fiSlicesList;
    }
}
